package com.tramy.aliyunoss;

import android.util.Log;

import androidx.annotation.NonNull;

import com.alibaba.sdk.android.oss.ClientException;
import com.alibaba.sdk.android.oss.OSS;
import com.alibaba.sdk.android.oss.OSSClient;
import com.alibaba.sdk.android.oss.ServiceException;
import com.alibaba.sdk.android.oss.callback.OSSCompletedCallback;
import com.alibaba.sdk.android.oss.common.auth.OSSCustomSignerCredentialProvider;
import com.alibaba.sdk.android.oss.model.ObjectMetadata;
import com.alibaba.sdk.android.oss.model.PutObjectRequest;
import com.alibaba.sdk.android.oss.model.PutObjectResult;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.module.annotations.ReactModule;

import java.io.IOException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

@ReactModule(name = AliyunOssModule.NAME)
public class AliyunOssModule extends ReactContextBaseJavaModule {

    public static final String NAME = "AliyunOss";

    private static final int SUCCESS = 100;
    private static final int ERROR = 101;

    private OSS oss;

    private final OkHttpClient okHttpClient;

    public AliyunOssModule(ReactApplicationContext reactContext) {
        super(reactContext);

        okHttpClient = new OkHttpClient();
    }

    @Override
    @NonNull
    public String getName() {
        return NAME;
    }

    @Override
    public Map<String, Object> getConstants() {
        Map<String, Object> constants = new HashMap<>();
        constants.put("SUCCESS", SUCCESS);
        constants.put("ERROR", ERROR);
        return constants;
    }

    @ReactMethod
    public void initWithSigner(String endPoint,
                               String signUrl) {
        OSSCustomSignerCredentialProvider credentialProvider = new OSSCustomSignerCredentialProvider() {
            @Override
            public String signContent(String content) {
                try {
                    String reqUrl = signUrl
                        + "?content=" + URLEncoder.encode(content, "UTF-8");

                    Request request = new Request.Builder()
                                              .url(reqUrl)
                                              .build();

                    Response response = okHttpClient.newCall(request).execute();

                    if (response.body() == null) {
                        return "";
                    }else {
                        return response.body().string();
                    }
                } catch (IOException e) {
                    Log.e(NAME, "sign error：" + e.toString());

                    return "";
                }
            }
        };

        oss = new OSSClient(
            getReactApplicationContext().getApplicationContext(), endPoint, credentialProvider);
    }

    @ReactMethod
    public void asyncUpload(String bucket,
                            String key,
                            String path,
                            Promise promise) {
        PutObjectRequest put = new PutObjectRequest(bucket, key, path);

        putObject(put, promise);
    }

    @ReactMethod
    public void asyncUploadPublic(String bucket,
                                  String key,
                                  String path,
                                  Promise promise) {
        PutObjectRequest put = new PutObjectRequest(bucket, key, path);

        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setHeader("x-oss-object-acl", "public-read");
        put.setMetadata(metadata);

        putObject(put, promise);
    }

    private void putObject(PutObjectRequest put,
                           Promise promise) {
        oss.asyncPutObject(put, new OSSCompletedCallback<PutObjectRequest, PutObjectResult>() {
            @Override
            public void onSuccess(PutObjectRequest request,
                                  PutObjectResult result) {
                promise.resolve(SUCCESS);
            }

            @Override
            public void onFailure(PutObjectRequest request,
                                  ClientException clientException,
                                  ServiceException serviceException) {
                promise.resolve(ERROR);

                if (clientException != null) {
                    Log.e(NAME, "upload error：" + clientException.toString());
                }

                if (serviceException != null) {
                    Log.e(NAME, "upload error：" + serviceException.toString());
                }
            }
        });
    }

}
